
#include <BPainter>
#include <BMouseEvent>
#include <BKeyEvent>

#include "PixmapArea.h"
#include "DragLayerFilter.h"

DragLayerFilter::DragLayerFilter() : BEventFilter("DragLayerFilter")
{
	_dragPart = Part_None;
	_dirtyRects = false;

}
DragLayerFilter::~DragLayerFilter()
{

}

void DragLayerFilter::applyPartDraging(const BPoint& pos)
{
	PixmapArea* pixmapArea = dynamic_cast<PixmapArea*>(this->host());
	BPoint offset = pos - _dragPoint;

	BWidgetSet selectedWidgets = pixmapArea->selectedWidgets();
	BRect area = pixmapArea->area();
	double scale = 100.0 / pixmapArea->zoom();
	if (_dragPart == Part_Center)
	{
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRectd layerRect = _originRects[i];
			layerRect += offset * scale;
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Left)
	{
		BRect rect = _dragRect;
		rect.left() = rect.left() + offset.x();
		BPointd origin = _dragRect.rightCenter() - area.pos();
		origin *= scale;
		double ratio = (double)rect.width() / _dragRect.width();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRectd layerRect = _originRects[i];
			layerRect.scale(origin, ratio, 1.0);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Top)
	{
		BRect rect = _dragRect;
		rect.top() += offset.y();
		BPointd origin = (_dragRect.bottomCenter() - area.pos()) * scale;
		double ratio = (double)rect.height() / _dragRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRectd layerRect = _originRects[i];
			layerRect.scale(origin, 1.0, ratio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Right)
	{
		BRect rect = _dragRect;
		rect.right() += offset.x();
		BPoint origin = (_dragRect.leftCenter() - area.pos()) * scale;
		double ratio = (double)rect.width() / _dragRect.width();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _originRects[i];
			layerRect.scale(origin, ratio, 1.0);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_Bottom)
	{
		BRect rect = _dragRect;
		rect.bottom() += offset.y();
		BPoint origin = (_dragRect.topCenter() - area.pos()) * scale;
		double ratio = (double)rect.height() / _dragRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _originRects[i];
			layerRect.scale(origin, 1.0, ratio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_LeftTop)
	{
		BRect rect = _dragRect;
		rect.left() += offset.x();
		rect.top() += offset.y();
		BPoint origin = (_dragRect.rightBottom() - area.pos()) * scale;
		double wratio = (double)rect.width() / _dragRect.width();
		double hRatio = (double)rect.height() / _dragRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _originRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_LeftBottom)
	{
		BRect rect = _dragRect;
		rect.left() += offset.x();
		rect.bottom() += offset.y();
		BPoint origin = (_dragRect.rightTop() - area.pos()) * scale;
		double wratio = (double)rect.width() / _dragRect.width();
		double hRatio = (double)rect.height() / _dragRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _originRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_RightTop)
	{
		BRect rect = _dragRect;
		rect.right() += offset.x();
		rect.top() += offset.y();
		BPoint origin = (_dragRect.leftBottom() - area.pos()) * scale;
		double wratio = (double)rect.width() / _dragRect.width();
		double hRatio = (double)rect.height() / _dragRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _originRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
	if (_dragPart == Part_RightBottom)
	{
		BRect rect = _dragRect;
		rect.right() += offset.x();
		rect.bottom() += offset.y();
		BPoint origin = (_dragRect.leftTop() - area.pos()) * scale;
		double wratio = (double)rect.width() / _dragRect.width();
		double hRatio = (double)rect.height() / _dragRect.height();
		for (int i = 0; i < selectedWidgets.size(); i++)
		{
			BWidget* layer = selectedWidgets[i];
			BRect layerRect = _originRects[i];
			layerRect.scale(origin, wratio, hRatio);
			layer->setRect(layerRect);
		}
		return;
	}
}

void DragLayerFilter::slotZoomChanged()
{
	_dirtyRects = true;
}
void DragLayerFilter::slotWidgetMoved(BObject* object, const BValue& value)
{
	_dirtyRects = true;
	this->fresh();
}
void DragLayerFilter::slotWidgetSelectionChanged(BObject* object, const BValue& value)
{
	BWidgetSet& selection = value;
	_dirtyRects = true;
	this->fresh();
}

void DragLayerFilter::attached(BWidget* widget)
{
	_dirtyRects = true;
	connect(widget, "zoom-changed", &DragLayerFilter::slotZoomChanged);
	connect(widget, "layer-moved", &DragLayerFilter::slotWidgetMoved);
	connect(widget, Signal_SelectionChanged, &DragLayerFilter::slotWidgetSelectionChanged);
	BEventFilter::attached(widget);
}
void DragLayerFilter::detached(BWidget* widget)
{
	disconnect(widget);
	BEventFilter::detached(widget);
}

void DragLayerFilter::updateEvent(const BEvent& event)
{

}

void DragLayerFilter::freshEvent(const BEvent& event)
{
	PixmapArea* pixmapArea = dynamic_cast<PixmapArea*>(this->host());
	if (_dirtyRects)
	{
		BRect area = pixmapArea->area();
		BWidgetSet& selectedWidgets = pixmapArea->selectedWidgets();
		if (selectedWidgets.size())
		{
			float ratio = pixmapArea->zoom() / 100.0f;
			BWidget* first = selectedWidgets.min();
			BRect rect = first->rect() * ratio + area.pos();
			for (int i = 1; i < selectedWidgets.size(); i++)
			{
				BWidget* layer = selectedWidgets[i];
				BRect layerRect = layer->rect() * ratio + area.pos();
				rect.expand(layerRect);
			}
			int b = 5;
			_partRectMap[Part_None] = rect;
			_partRectMap[Part_Left] = BRect(-b, b, b + b, rect.height() - b - b) + rect.pos();
			_partRectMap[Part_Top] = BRect(b, -b, rect.width() - b - b, b + b) + rect.pos();
			_partRectMap[Part_Right] = BRect(rect.width() - b, b, b + b, rect.height() - b - b) + rect.pos();
			_partRectMap[Part_Bottom] = BRect(b, rect.height() - b, rect.width() - b - b, b + b) + rect.pos();
			_partRectMap[Part_Center] = BRect(b, b, rect.width() - b - b, rect.height() - b - b) + rect.pos();
			_partRectMap[Part_LeftTop] = BRect(-b, -b, b + b, b + b) + rect.pos();
			_partRectMap[Part_LeftBottom] = BRect(-b, rect.height() - b, b + b, b + b) + rect.pos();
			_partRectMap[Part_RightTop] = BRect(rect.width() - b, -b, b + b, b + b) + rect.pos();
			_partRectMap[Part_RightBottom] = BRect(rect.width() - b, rect.height() - b, b + b, b + b) + rect.pos();
		}
		else
		{
			_partRectMap.reset();
		}
		_dirtyRects = false;
	}
}
void DragLayerFilter::paintEvent(const BEvent& event)
{
	if (_partRectMap.size())
	{
		BPainter painter(this->host());
		if (_draging)
		{
			painter.setLineStipple(0x0F0F);
			painter.setColor(0, 200, 0);
			painter.drawRect(_partRectMap(Part_None));
			painter.setLineStipple(0);
		}
		else
		{
			painter.setColor(0, 128, 0);
			painter.drawRect(_partRectMap(Part_None));
		}
	}
}

void DragLayerFilter::mouseEnterEvent(const BMouseEvent& mouseEvent)
{

}
void DragLayerFilter::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{

}

void DragLayerFilter::mousePressEvent(const BMouseEvent& mouseEvent)
{
	PixmapArea* pixmapArea = dynamic_cast<PixmapArea*>(this->host());
	if (mouseEvent.button() == Button_Left)
	{
		if (_dragPart)
		{
			_draging = true;
			_dragPoint = mouseEvent.pos();
			_dragRect = _partRectMap[Part_None];
			BWidgetSet& selectedWidgets = pixmapArea->selectedWidgets();
			_originRects.resize(selectedWidgets.size());
			for (int i = 0; i < selectedWidgets.size(); i++)
			{
				_originRects[i] = selectedWidgets[i]->rect();
			}
			mouseEvent.accept();
		}
	}
}
void DragLayerFilter::mouseReleaseEvent(const BMouseEvent& mouseEvent)
{
	PixmapArea* pixmapArea = dynamic_cast<PixmapArea*>(this->host());
	if (mouseEvent.button() == Button_Left)
	{
		if (_draging)
		{
			_draging = false;
			pixmapArea->setCursor(Cursor_None);
			if (mouseEvent.button() == Button_Left)
			{
				_dragPart = Part_None;
				_originRects.clear();
				_dirtyRects = true;
			}
		}
		mouseEvent.accept();
	}
}
void DragLayerFilter::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	PixmapArea* pixmapArea = dynamic_cast<PixmapArea*>(this->host());
	if (_draging && mouseEvent.button() == Button_Left)
	{
		applyPartDraging(pos);
		_dirtyRects = true;
		pixmapArea->fresh();
		mouseEvent.accept();
		return;
	}
	_dragPart = Part_None;
	if (mouseEvent.button() == Button_None)
	{
		BRect area = pixmapArea->area();
		BPixmap* pixmap = pixmapArea->pixmap();
		float ratio = pixmapArea->zoom() / 100.0f;
		for (auto it = _partRectMap.begin(); it < _partRectMap.end(); it++)
		{
			if (it.key() > Part_None && it->contain(pos))
			{
				_dragPart = it.key();
				break;
			}
		}
		if (_dragPart == Part_None)
			pixmapArea->setCursor(Cursor_None);
		else if (_dragPart == Part_Center)
			pixmapArea->setCursor(Cursor_SizeAll);
		else if (_dragPart == Part_Left || _dragPart == Part_Right)
			pixmapArea->setCursor(Cursor_SizeHor);
		else if (_dragPart == Part_Top || _dragPart == Part_Bottom)
			pixmapArea->setCursor(Cursor_SizeVer);
		else if (_dragPart == (Part_Left | Part_Top))
			pixmapArea->setCursor(Cursor_SizeLeftTop);
		else if (_dragPart == (Part_Left | Part_Bottom))
			pixmapArea->setCursor(Cursor_SizeLeftBottom);
		else if (_dragPart == (Part_Right | Part_Top))
			pixmapArea->setCursor(Cursor_SizeRightTop);
		else if (_dragPart == (Part_Right | Part_Bottom))
			pixmapArea->setCursor(Cursor_SizeRightBottom);
	}
	if (_dragPart)
		mouseEvent.accept();
}
void DragLayerFilter::mouseWheelEvent(const BMouseEvent& mouseEvent)
{

}
